package com.ermace.robo.jumper.game;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;

import com.ermace.robo.jumper.Loadable;
import com.ermace.robo.jumper.game.GameObjects.Drawable;
import com.ermace.robo.jumper.game.GameObjects.GameObject;

/**
 * A class representing a map for the game.
 * 
 * @note	This class is not a enum because it might be cool if there was
 * 			a map-editor later.
 */
public class Map implements Loadable, Drawable {

	@SuppressLint("UseSparseArrays")
	private final HashMap<Integer, Bitmap> bitmaps = new HashMap<Integer, Bitmap>();
	private boolean loaded = false;
	
	private List<GameObject> objects;
	private String mapName;
	private boolean unlocked;
	private int imgId;
	private int bgId;
	private int titleId;
	
	private boolean bottomLess = false;
	private boolean meteorites = false;
	private boolean fireball = false;
	
	public Map(int imgId, String mapName, int bgId, int titleId, boolean unlocked, List<GameObject> objects) {
		if (objects != null)
			this.objects = new ArrayList<GameObject>(objects);
		else
			this.objects = new ArrayList<GameObject>();
		
		this.unlocked = unlocked;
		this.imgId = imgId;
		this.mapName = mapName;
		this.bgId = bgId;
		this.titleId = titleId;
	}
	
	public Map(int imgId, String mapName, int bgId, int titleId, boolean unlocked) {
		this(imgId, mapName, bgId, titleId, unlocked, null);
	}
	
	public Map(int imgId, String mapName, int bgId, int titleId)
	{
		this(imgId, mapName, bgId, titleId, true, null);
	}
	
	/**
	 *
	 * Constructor to use when re-constructing object
	 * from a parcel
	 *
	 * @param in a parcel from which to read this object
	 */
	public Map(Parcel in) {
		readFromParcel(in);
	}

	public void addObject(GameObject obj)
	{
		if (! objects.contains(obj))
			objects.add(obj);
	}
	
	public List<GameObject> getObjects()
	{
		return new ArrayList<GameObject>(objects);
	}
	
	public String getName()
	{
		return mapName;
	}
	
	public int getImageId()
	{
		return imgId;
	}
	
	public boolean isUnlocked() {
		return unlocked;
	}
	
	public int getBgId()
	{
		return bgId;
	}
	
	/**
	 * 
	 * @return	The background for this map if the map is loaded
	 * 			else null.
	 */
	public Bitmap getBackground() {
		return bitmaps.get(bgId);
	}
	
	public int getTitleId()
	{
		return titleId;
	}
	
	public boolean isLoaded() {
		return loaded;
	}
	
	/**
	 * Loads the bitmaps of the map and the objects in memory.
	 */
	@Override
	public void load(Resources res) {
		bitmaps.put(bgId, BitmapFactory.decodeResource(res, bgId));
//		bitmaps.append(imgId, BitmapFactory.decodeResource(res, imgId));		TODO niet nodig denk ik.
//		bitmaps.append(titleId, BitmapFactory.decodeResource(res, titleId));
		
		for(GameObject object: objects) {
			int id = object.getPictureId();
			if (bitmaps.get(id) == null)
				bitmaps.put(id, BitmapFactory.decodeResource(res, id));
		}
		
		loaded = true;
	}
	
	/**
	 * Removes the bitmaps from memory.
	 */
	public void unload() {
		bitmaps.clear();
		loaded = false;
	}
	
	@Override
	public void draw(Canvas canvas) {
		canvas.drawBitmap(bitmaps.get(bgId), null, new Rect(0, 0, canvas.getWidth(), canvas.getHeight()), null);
		
		for(GameObject object: objects)
			canvas.drawBitmap(bitmaps.get(object.getPictureId()), null, object.getRect(), null);
	}
	
	
	/**
    *
    * This field is needed for Android to be able to
    * create new objects, individually or as arrays.
    *
    * This also means that you can use use the default
    * constructor to create the object and use another
    * method to hyrdate it as necessary.
    *
    */
	public static final Parcelable.Creator<Map> CREATOR =
			new Parcelable.Creator<Map>() {
		@Override
		public Map createFromParcel(Parcel in) {
			return new Map(in);
		}

		@Override
		public Map[] newArray(int size) {
			return new Map[size];
		}
	};

	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}
	
	@Override
	public void writeToParcel(Parcel dest, int flags) {
		
		GameObject[] objectsContainer = new GameObject[objects.size()];
		objects.toArray(objectsContainer);
		dest.writeParcelableArray(objectsContainer, flags);
		
		dest.writeString(mapName);
		
		boolean[] container = {unlocked};
		dest.writeBooleanArray(container);
		
		dest.writeInt(imgId);
		dest.writeInt(bgId);
		dest.writeInt(titleId);
	}
	
	private void readFromParcel(Parcel in) {
		
		Parcelable[] parcelContainer = in.readParcelableArray(GameObject.class.getClassLoader());
		GameObject[] objectsContainer = new GameObject[parcelContainer.length];
		for (int index = 0; index < parcelContainer.length; index++)
			objectsContainer[index] = (GameObject) parcelContainer[index];
		
		objects = new ArrayList<GameObject>();
		for (GameObject object: objectsContainer)
			objects.add(object);
		
		mapName = in.readString();
		
		boolean[] container = new boolean[1];
		in.readBooleanArray(container);
		unlocked = container[0];
		
		imgId = in.readInt();
		bgId = in.readInt();
		titleId = in.readInt();
	}

	public boolean isBottomLess() {
		return bottomLess;
	}

	public void setBottomLess(boolean bottomLess) {
		this.bottomLess = bottomLess;
	}

	public boolean hasMeteorites() {
		return meteorites;
	}

	public void setHasMeteorites(boolean meteorites) {
		this.meteorites = meteorites;
	}

	public boolean hasFireball() {
		return fireball;
	}

	public void setHasFireball(boolean fireball) {
		this.fireball = fireball;
	}
}
